from rest_framework import serializers
from django.contrib.auth.models import User
from django_redis import get_redis_connection
from jt32.settings import CACHES
from config.dbs.redisConfig import KEY_TEMPLATE
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
from .models import UserDetail, Area, Address
import re


# 新设详情类
# class UserDetailSerializerSimple(serializers.ModelSerializer):
#     # 指定模型和展示字段
#     class Meta:
#         model = UserDetail
#         exclude = ['is_delete', 'id', "create_time", "update_time", 'user', "avatar"]


# 定于用户序列化器
class UserSerializer(serializers.ModelSerializer):
    verify = serializers.CharField(write_only=True, label='验证码')
    uuid = serializers.CharField(write_only=True, label='uuid')

    # 从外键字段中的用户详情表反向查询出性别、生日、手机号
    sex = serializers.IntegerField(source='userdetail.sex', read_only=True, label='性别')
    birthday = serializers.DateField(source='userdetail.birthday', read_only=True, label='生日')
    phone = serializers.CharField(source='userdetail.phone', read_only=True, label='手机号')
    # 增加上了头像的数据返回
    avatar = serializers.CharField(source='userdetail.avatar', read_only=True, label='头像')
    # userdetail = UserDetailSerializerSimple(read_only=True)


    class Meta:
        model = User
        # fields = '__all__'
        exclude = [
            "first_name", "groups", "date_joined"
            , "last_name", "user_permissions", "is_staff",
            "is_active", "id"
        ]
        extra_kwargs = {
            'password': {'write_only': True},
            'is_superuser': {'read_only': True}
        }

    # 自定义校验方法
    def validate(self, attrs):
        # 获取前端验证码
        verify = attrs.get('verify')
        # 获取前端uuid
        uuid = attrs.get('uuid')
        # 从redis数据库获取数据
        cache = get_redis_connection(alias='verify_codes')
        redis_verify = cache.get(KEY_TEMPLATE % ('register', uuid))
        # 查询一次后直接从数据库删除
        cache.delete(KEY_TEMPLATE % ('register', uuid))
        # 判断后端数据库是否存在验证码
        if not redis_verify:
            raise serializers.ValidationError('验证码已过期')
        # 判断和前端验证码是否一样
        if redis_verify.upper() != verify.upper():
            raise serializers.ValidationError('验证码错误')
        # 返回数据
        return attrs


# 登录校验序列化器(自带的只可以进行校验用户名和密码不够用,要重写一个可以对验证码和uuid进行验证)
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    # 获取验证码和uuid
    verify = serializers.CharField(write_only=True, label='验证码')
    uuid = serializers.CharField(write_only=True, label='uuid')

    # 重写校验方法
    def validate(self, attrs):
        # 获取前端传来的数据
        verify = attrs.get('verify')
        uuid = attrs.get('uuid')
        username = attrs.get('username')
        password = attrs.get('password')
        # 从redis数据库进行校验
        cache = get_redis_connection(alias='verify_codes')
        redis_verify = cache.get(KEY_TEMPLATE % ('login', uuid))
        # 查询一次后直接从数据库删除
        cache.delete(KEY_TEMPLATE % ('login', uuid))
        # 判断后端数据库是否存在验证码
        if not redis_verify:
            raise serializers.ValidationError('验证码已过期')
        # 判断和前端验证码是否一样
        if redis_verify.upper() != verify.upper():
            raise serializers.ValidationError('验证码错误')
        # 对用户名和密码进行校验
        user = authenticate(username=username, password=password)
        if not user:
            raise serializers.ValidationError('用户名或密码错误')
        # 制作token令牌并返回
        refresh = self.get_token(user)
        return {'username': username, 'token': str(refresh.access_token)}


# 用户详情的序列化器
class UserDetailSerializer(serializers.ModelSerializer):
    # 指定模型和展示字段
    class Meta:
        model = UserDetail
        exclude = ['is_delete', 'id']


# 用于修改密码的序列化器
class UpdatePasswordSerializer(serializers.Serializer):
    # 修改密码用于的字段
    password = serializers.CharField(max_length=20, min_length=6, label='密码')
    new_password = serializers.CharField(max_length=20, min_length=6, label='新密码')
    re_new_password = serializers.CharField(max_length=20, min_length=6, label='确认新密码')
    # 进行校验

    def validate(self, attrs):
        # 校验新密码和确认新密码是否一致
        if attrs.get('new_password') != attrs.get('re_new_password'):
            raise serializers.ValidationError('两次密码不一致')
        # 校验新密码和旧密码是否一致
        if attrs.get('password') == attrs.get('new_password'):
            raise serializers.ValidationError('新密码不能和旧密码一样')
        # 判断和数据库中的密码是否一致
        user = self.context.get('request').user
        if not user.check_password(attrs.get('password')):
            raise serializers.ValidationError('原密码错误')
        return attrs


# 地址省市区序列化器
class AreaSerializer(serializers.ModelSerializer):
    # 设置模型和展示字段
    class Meta:
        model = Area
        fields = ['id', 'name']


# retrieve下的子级查询序列化器
class AreaSerializerSimple(serializers.ModelSerializer):
    # 子级序列化数据
    area_set = AreaSerializer(many=True, read_only=True)

    # 模型和字段
    class Meta:
        model = Area
        fields = ['id', 'name', 'area_set']


# 地址详情序列化器
class AddressSerializer(serializers.ModelSerializer):
    # 展示省、市、区的数据回去
    province_name = serializers.CharField(source='province.name', read_only=True)
    city_name = serializers.CharField(source='city.name', read_only=True)
    district_name = serializers.CharField(source='district.name', read_only=True)

    # 增加对手机号校验的方法
    def validate_mobile(self, values):
        if not re.match(r'1[3-9]\d{9}', values):
            raise serializers.ValidationError('手机号格式错误')
        return values

    # 模型和字段
    class Meta:
        model = Address
        exclude = ['is_delete']
